package org.jsola.hr.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.apache.commons.lang3.StringUtils;
import org.jsola.core.Page;
import org.jsola.exception.ParamException;
import org.jsola.hr.common.ExampleKit;
import org.jsola.hr.constant.HrConstants;
import org.jsola.hr.dao.IChildCompanyDAO;
import org.jsola.hr.dao.IGroupCompanyDAO;
import org.jsola.hr.dto.GroupCompanyAddDTO;
import org.jsola.hr.dto.GroupCompanyUpdateDTO;
import org.jsola.hr.entity.ChildCompanyDO;
import org.jsola.hr.entity.CompanyDO;
import org.jsola.hr.entity.CostBillDO;
import org.jsola.hr.entity.GroupCompanyDO;
import org.jsola.hr.provider.IPermissionGroupProviderService;
import org.jsola.hr.query.CompanyQuery;
import org.jsola.hr.query.GroupCompanyQuery;
import org.jsola.hr.service.IChildCompanyService;
import org.jsola.hr.service.ICompanyService;
import org.jsola.hr.service.ICostBillService;
import org.jsola.hr.service.IGroupCompanyService;
import org.jsola.hr.vo.*;
import org.jsola.permission.entity.GroupDO;
import org.jsola.permission.service.IGroupService;
import org.jsola.user.core.TokenUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import tk.mybatis.mapper.entity.Example;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 子公司分管公司关系表
 *
 * @author zhr
 */
@Service("hrGroupCompanyServiceImpl")
public class GroupCompanyServiceImpl implements IGroupCompanyService {

    @Autowired
    private IGroupCompanyDAO groupCompanyDAO;

    @Autowired
    private IPermissionGroupProviderService groupService;

    @Autowired
    private ICompanyService companyService;

    @Autowired
    private ICostBillService costBillService;

    @Autowired
    private IChildCompanyService childCompanyService;

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public GroupCompanyVO save(GroupCompanyAddDTO groupCompanyAddDTO, TokenUser tokenUser) {
        // 转DO
        GroupCompanyDO groupCompanyDO = groupCompanyAddDTO.to(GroupCompanyDO.class);
        // 保存
        groupCompanyDO = save(groupCompanyDO, tokenUser.getSiteId(), tokenUser.getUserId());
        return groupCompanyDO.to(GroupCompanyVO.class);
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public List<GroupCompanyVO> batchSave(List<GroupCompanyAddDTO> groupCompanyAddDTOList, TokenUser tokenUser) {
        if (CollectionUtils.isEmpty(groupCompanyAddDTOList)) {
            return null;
        }
        String groupId = groupCompanyAddDTOList.get(0).getGroupId();
        // 校验组
        checkGroupExis(groupId, tokenUser.getSiteId());
        // 先删除旧的
        deleteByGroup(groupId, tokenUser);

        List<GroupCompanyDO> groupCompanyDOList = groupCompanyAddDTOList
                .parallelStream()
                .map(groupCompanyAddDTO -> {
                    GroupCompanyDO groupCompanyDO = groupCompanyAddDTO.to(GroupCompanyDO.class);
                    groupCompanyDO.setGroupId(groupId);
                    groupCompanyDO.preInsert(tokenUser.getUserId());
                    groupCompanyDO.setSiteId(tokenUser.getSiteId());
                    return groupCompanyDO;
                }).collect(Collectors.toList());
        groupCompanyDAO.insertListAndSetId(groupCompanyDOList);
        return groupCompanyDOList
                .parallelStream()
                .map(groupCompanyDO -> groupCompanyDO.to(GroupCompanyVO.class))
                .collect(Collectors.toList());
    }

    /**
     * 校验组是否存在
     *
     * @param groupId 组id
     * @param siteId  站点
     */
    private void checkGroupExis(String groupId, String siteId) {
        if ("0".equals(groupId)) {
            return;
        }
        GroupDO groupDO = groupService.selectDOById(groupId, siteId);
        ParamException.notNull(groupDO, "分组不存在或已删除");
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public int update(GroupCompanyUpdateDTO groupCompanyUpdateDTO, TokenUser tokenUser) {
        //转DO
        GroupCompanyDO groupCompanyDO = groupCompanyUpdateDTO.to(GroupCompanyDO.class);
        //根据主键更新，只更新非null值
        return updateByIdSelective(groupCompanyDO, tokenUser.getSiteId(), tokenUser.getUserId());
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public int deleteByIds(TokenUser tokenUser, String... groupCompanyIds) {
        return deleteByIds(tokenUser.getSiteId(), tokenUser.getUserId(), (Object[]) groupCompanyIds);
    }


    @Override
    public GroupCompanyVO selectById(String groupCompanyId, String siteId) {
        GroupCompanyDO groupCompanyDO = selectDOById(groupCompanyId, siteId);
        if (groupCompanyDO == null) {
            return null;
        }
        return groupCompanyDO.to(GroupCompanyVO.class);
    }

    @Override
    public List<GroupCompanyListVO> select(GroupCompanyQuery groupCompanyQuery, String siteId) {
        List<GroupCompanyDO> groupCompanyDOList = selectDO(groupCompanyQuery, siteId);
        if (CollectionUtils.isEmpty(groupCompanyDOList)) {
            return groupCompanyDOList == null ? null : new ArrayList<>();
        }
        return groupCompanyDOList.stream()
                .map(groupCompanyDO -> groupCompanyDO.to(GroupCompanyListVO.class))
                .collect(Collectors.toList());
    }

    @Override
    public int selectCount(GroupCompanyQuery groupCompanyQuery, String siteId) {
        Example example = buildExample(groupCompanyQuery, siteId);
        return groupCompanyDAO.selectCountByExample(example);
    }

    @Override
    public Page<GroupCompanyListVO> selectPage(GroupCompanyQuery groupCompanyQuery, String siteId) {
        Example example = buildExample(groupCompanyQuery, siteId);
        Page<GroupCompanyDO> page = groupCompanyDAO.selectPageByExample(example,
                groupCompanyQuery.getPageNo(),
                groupCompanyQuery.getPageSize());

        return page.to(GroupCompanyListVO.class);
    }

    @Override
    public GroupCompanyDO selectDOById(String groupCompanyId, String siteId) {
        return listById(groupCompanyId, siteId);
    }

    @Override
    public List<GroupCompanyDO> selectDO(GroupCompanyQuery groupCompanyQuery, String siteId) {
        Example example = buildExample(groupCompanyQuery, siteId);
        return groupCompanyDAO.selectByExample(example);
    }

    @Override
    public List<GroupCompanyDO> listByGroupId(String groupId, String siteId) {
        return selectByGroupIds(Collections.singletonList(groupId), siteId);
    }

//    @Override
//    public List<GroupCompanyDO> selectByGroupIds(List<String> groupIds, String siteId) {
//        if (CollectionUtils.isEmpty(groupIds)) {
//            return new ArrayList<>();
//        }
//        Example example = new Example(GroupCompanyDO.class);
//        example.and()
//                .andIn("groupId", groupIds)
//                .andEqualTo("siteId", siteId);
//        return groupCompanyDAO.selectByExample(example);
//    }

    @Override
    public List<GroupCompanyDO> selectByGroupIds(List<String> groupIds, String siteId) {
        if (CollectionUtils.isEmpty(groupIds)) {
            return new ArrayList<>();
        }

        //根据groupIds查询整个分组树
        List<String> groupTreeIds = childCompanyService.groupTreeIds(groupIds, siteId);

        Example example = new Example(GroupCompanyDO.class);
        example.and()
                .andIn("groupId", groupTreeIds)
                .andEqualTo("siteId", siteId);
        return groupCompanyDAO.selectByExample(example);
    }

    @Override
    public List<String> selectCompanyIdsByGroupIds(List<String> groupIds, String siteId) {
        List<GroupCompanyDO> groupCompanyDOList = selectByGroupIds(groupIds, siteId);
        return groupCompanyDOList.parallelStream()
                .map(GroupCompanyDO::getCompanyId).distinct().collect(Collectors.toList());
    }

    @Override
    public List<GroupCompanyDO> selectAllCompanyGroupByGroupIds(List<String> groupIds, String siteId) {
        if (CollectionUtils.isEmpty(groupIds)) {
            return new ArrayList<>();
        }
        Example example = new Example(GroupCompanyDO.class);
        example.and()
                .andIn("groupId", groupIds)
                .orEqualTo("isAll", true)
                .andEqualTo("siteId", siteId);
        return groupCompanyDAO.selectByExample(example);
    }

    @Override
    public List<GroupCompanyDO> selectByCompanyIds(List<String> companyIds, String siteId) {
        if (CollectionUtils.isEmpty(companyIds)) {
            return new ArrayList<>();
        }
        Example example = new Example(GroupCompanyDO.class);
        example.and()
                .andEqualTo("siteId", siteId);
        example.and()
                .orIn("companyId", companyIds)
                .orEqualTo("isAll", true);
        return groupCompanyDAO.selectByExample(example);
    }

    @Override
    public int selectCountByCompanyIds(List<String> companyIds, String siteId) {
        List<GroupCompanyDO> groupCompanyDOList = selectByCompanyIds(companyIds, siteId);
        if (!CollectionUtils.isEmpty(groupCompanyDOList)) {
            // 去重
            List<String> groupIdList = groupCompanyDOList.parallelStream()
                    .map(GroupCompanyDO::getGroupId)
                    .distinct()
                    .collect(Collectors.toList());
            return groupIdList.size();
        }
        return 0;
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public int deleteByGroup(String groupId, TokenUser tokenUser) {
        List<GroupCompanyDO> groupCompanyList = listByGroupId(groupId, tokenUser.getSiteId());
        if (CollectionUtils.isEmpty(groupCompanyList)) {
            return 0;
        }
        String[] groupCompanyIds = groupCompanyList.parallelStream().map(GroupCompanyDO::getId).toArray(String[]::new);
        return deleteByIds(tokenUser, groupCompanyIds);
    }

    @Override
    public List<String> checkCompanyIsChild(String companyId, String siteId) {
        Example example = new Example(GroupCompanyDO.class);
        example.and().andEqualTo("siteId", siteId);
        // 分管全部用工单位或管理当前用工单位
        example.and()
                .orEqualTo("isAll", true)
                .orEqualTo("companyId", companyId);

        List<GroupCompanyDO> groupCompanyList = groupCompanyDAO.selectByExample(example);
        if (CollectionUtils.isEmpty(groupCompanyList)) {
            return null;
        }
        return groupCompanyList.stream().map(GroupCompanyDO::getGroupId).collect(Collectors.toList());
    }

    @Override
    public List<String> listHasRoleInCompany(List<String> groupList, String childCompanyId, String siteId) {
        if (StringUtils.isEmpty(childCompanyId) || CollectionUtils.isEmpty(groupList)) {
            return new ArrayList<>();
        }
        Example example = new Example(GroupCompanyDO.class);
        example.and()
                .andIn("groupId", groupList)
                .andEqualTo("siteId", siteId);

        // 分管全部用工单位或管理当前用工单位
        example.and()
                .orEqualTo("isAll", true)
                .orEqualTo("companyId", childCompanyId);

        List<GroupCompanyDO> groupCompanyList = groupCompanyDAO.selectByExample(example);
        if (CollectionUtils.isEmpty(groupCompanyList)) {
            return null;
        }
        return groupCompanyList.stream().map(GroupCompanyDO::getGroupId).collect(Collectors.toList());
    }

    @Override
    public Boolean groupHasRoleInCompany(String groupId, String childCompanyId, String siteId) {
        Example example = new Example(GroupCompanyDO.class);
        example.and()
                .andEqualTo("groupId", groupId)
                .andEqualTo("siteId", siteId);

        // 分管全部用工单位或管理当前用工单位
        example.and()
                .orEqualTo("isAll", true)
                .orEqualTo("companyId", childCompanyId);

        GroupCompanyDO groupCompanyDO = groupCompanyDAO.selectOneByExample(example);
        return Objects.nonNull(groupCompanyDO);
    }

    @Override
    public List<String> selectCompanyIdListByGroupId(String companyGroupId, String siteId) {
        return selectCompanyIdsByGroupIds(Collections.singletonList(companyGroupId), siteId);
    }

    @Override
    public List<String> selectCompanyIdListByGroupIds(List<String> childCompanyIds, String siteId) {
        return selectCompanyIdsByGroupIds(childCompanyIds, siteId);
    }

    @Override
    public List<CompanyDO> selectCompanyByCostBillId(Long costBillId, TokenUser tokenUser) {
        CostBillDO costBillDO = costBillService.selectDOById(costBillId, tokenUser.getSiteId());
        if (!costBillDO.getIsMerge()) {
            throw new ParamException("此账单不为用工单位分组级");
        }
        String companyId = costBillDO.getCompanyId();
        String[] companyIdArray = companyId.split(",");
        List<String> companyIdList = Arrays.asList(companyIdArray);
        return companyService.selectByIds(companyIdList, tokenUser.getSiteId());
    }

    /**
     * 查询分组下的用工单位集合（过滤登录人权限）
     * 选择某个分组，查询分组下的用工单位
     *   如果拥有全部权限：
     *     点击租户：    直接查询整个租户的用工单位集合
     *     点击某个分组：根据租户查询租户树，通过租户数，查询用工单位集合
     *   如果有部分权限：
     *     点击租户： 查询有权限的分组集合 + 有权限的用工单位  的用工单位集合
     *     点击某个分组： 根据分组查询分组树，然后过滤有权限的分组，根据分组集合查询用工单位集合
     * @param groupCompanyQuery
     * @param tokenUser
     * @return
     */
    @Override
    public Page<CompanyVO> companyListByGroupId(GroupCompanyQuery groupCompanyQuery, TokenUser tokenUser) {
        //判断当前用户，是否有当前分组权限，没有的话，返回空
        String groupId = groupCompanyQuery.getGroupId();
        //过滤当前登录人，有权限的用工单位分组和用工单位
        UserCompanyVO userCompanyVO = childCompanyService.selectByUserId(tokenUser.getUserId(), tokenUser.getSiteId());

        List<CompanyVO> list = new ArrayList<>();

        if (userCompanyVO.getIsAllChildCompany()) {
            //拥有全部用工单位权限
            if (groupId.equals("0")) {
                //查询租户级别
                if (groupCompanyQuery.getIsRecursion() == null || groupCompanyQuery.getIsRecursion()) {
                    //查询全部的用工单位
                    PageHelper.startPage(groupCompanyQuery.getPageNo(), groupCompanyQuery.getPageSize());
                    List<CompanyDO> companyDOList = companyService.selectBySiteId(tokenUser.getSiteId());
                    PageInfo<CompanyDO> companyDOPageInfo = new PageInfo<CompanyDO>(companyDOList);
                    list = companyDOList.stream().map(companyDO -> companyDO.to(CompanyVO.class)).collect(Collectors.toList());
                    return new Page<>(list, companyDOPageInfo.getPageNum(), companyDOPageInfo.getPageSize(), (int) companyDOPageInfo.getTotal());
                } else {
                    //查询直接挂在租户下的用工单位
                    CompanyQuery companyQuery = new CompanyQuery();
                    companyQuery.setPageNo(groupCompanyQuery.getPageNo());
                    companyQuery.setPageSize(groupCompanyQuery.getPageSize());
                    Page<CompanyVO> page = companyService.selectPageNotInGroup(companyQuery, tokenUser);
                    return page;
                }
            } else {
                //查询某个分组
                if (groupCompanyQuery.getIsRecursion() == null || groupCompanyQuery.getIsRecursion()) {
                    //递归查询分组下的用工单位
                    List<String> groupIdList = new ArrayList<>();
                    groupIdList.add(groupId);
                    List<String> groupIds = childCompanyService.groupTreeIds(groupIdList, tokenUser.getSiteId());
                    PageHelper.startPage(groupCompanyQuery.getPageNo(), groupCompanyQuery.getPageSize());
                    list = groupCompanyDAO.companyListByGroupIds(groupIds, tokenUser.getSiteId());
                    PageInfo<CompanyVO> pageInfo = new PageInfo<CompanyVO>(list);
                    return new Page<>(pageInfo.getList(), pageInfo.getPageNum(), pageInfo.getPageSize(), (int) pageInfo.getTotal());
                } else {
                    //查询直接下级的用工单位
                    List<String> groupIdList = new ArrayList<>();
                    groupIdList.add(groupId);
                    PageHelper.startPage(groupCompanyQuery.getPageNo(), groupCompanyQuery.getPageSize());
                    list = groupCompanyDAO.companyListByGroupIds(groupIdList, tokenUser.getSiteId());
                    PageInfo<CompanyVO> pageInfo = new PageInfo<CompanyVO>(list);
                    return new Page<>(pageInfo.getList(), pageInfo.getPageNum(), pageInfo.getPageSize(), (int) pageInfo.getTotal());
                }
            }

        } else {
            List<String> allGroupIds = userCompanyVO.getAllGroupIds();
            List<String> companyIds = userCompanyVO.getCompanyIds();
            if (groupId.equals("0")) {
                //查询有权限的分组 + 有权限的用工单位
                PageHelper.startPage(groupCompanyQuery.getPageNo(), groupCompanyQuery.getPageSize());
                list = groupCompanyDAO.companyListByGroupIdsOrCompanyIds(allGroupIds, companyIds, tokenUser.getSiteId());
                PageInfo<CompanyVO> pageInfo = new PageInfo<CompanyVO>(list);
                return new Page<>(pageInfo.getList(), pageInfo.getPageNum(), pageInfo.getPageSize(), (int) pageInfo.getTotal());
            } else {
                List<String> groupIdList = new ArrayList<>();
                groupIdList.add(groupId);
                //要查询的分组集合
                List<String> groupIds = childCompanyService.groupTreeIds(groupIdList, tokenUser.getSiteId());
                //过滤一下有权限的分组
                List<String> permissionGroupIds = groupIds.stream().filter(group -> allGroupIds.contains(group)).collect(Collectors.toList());
//
                //需要额外判断下，有权限的用工单位，所属的分组属于要查询的分组中
                Example example = new Example(GroupCompanyDO.class);
                example.and()
                        .andEqualTo("siteId", tokenUser.getSiteId())
                        .andIn("groupId", groupIds)
                        .andIn("companyId", companyIds);
                List<GroupCompanyDO> GroupCompanyList = groupCompanyDAO.selectByExample(example);
                //查询条件下，有权限的用工单位
                List<String> permissionCompanyIds = GroupCompanyList.stream().map(GroupCompanyDO::getCompanyId).collect(Collectors.toList());

                PageHelper.startPage(groupCompanyQuery.getPageNo(), groupCompanyQuery.getPageSize());
                list = groupCompanyDAO.companyListByGroupIdsOrCompanyIds(permissionGroupIds, permissionCompanyIds, tokenUser.getSiteId());
                PageInfo<CompanyVO> pageInfo = new PageInfo<CompanyVO>(list);
                return new Page<>(pageInfo.getList(), pageInfo.getPageNum(), pageInfo.getPageSize(), (int) pageInfo.getTotal());
            }
        }

    }


    /**
     * 根据查询参数，构建example
     *
     * @param groupCompanyQuery 查询参数
     * @param siteId            所属站点id
     * @return example
     */
    private Example buildExample(GroupCompanyQuery groupCompanyQuery, String siteId) {
        Example example = new Example(GroupCompanyDO.class);
        example.and()
                .andEqualTo("siteId", siteId);
        if (groupCompanyQuery.getGroupId() != null) {
            example.and().andEqualTo("groupId", groupCompanyQuery.getGroupId());
        }
        if (groupCompanyQuery.getCompanyId() != null) {
            example.and().andEqualTo("companyId", groupCompanyQuery.getCompanyId());
        }
        if (groupCompanyQuery.getIsAll() != null) {
            example.and().andEqualTo("isAll", groupCompanyQuery.getIsAll());
        }
        // 排序
        ExampleKit.setExampleOrder(example, groupCompanyQuery.getOrders());
        return example;
    }
}




